pub mod mp; // 公众号
pub mod open; // 开放平台

use serde_derive::Deserialize;
use serde_json::Value;

use super::{
    my_err::MyErr,
    {util, util_string},
};

#[derive(Clone, Deserialize)]
pub struct Wechat {
    pub test: bool,
    pub retoken: bool,
    pub appid: String,
    pub app_secret: String,
    pub aeskey: String,
    pub token: String,
    pub pay_key: String,
    pub serial_no: String,
    pub web_state: String,
}

impl Wechat {
    #[allow(dead_code)]
    pub fn get_open(&self) -> open::Open {
        return open::Open { wechat: self.clone() };
    }

    #[allow(dead_code)]
    pub fn get_mp(&self, authorizer_app_id: &str) -> mp::Mp {
        return mp::Mp {
            wechat: self.clone(),
            authorizer_app_id: authorizer_app_id.to_string(),
        };
    }

    // 验证消息的确来自微信服务器
    // 1）将token、timestamp、nonce、 msg 四个参数进行字典序排序
    // 2）将四个参数字符串拼接成一个字符串进行sha1加密
    // 3）开发者获得加密后的字符串可与msgSignature对比，标识该请求来源于微信
    #[allow(dead_code)]
    fn check_msg_signature(&self, signature: &str, timestamp: &str, nonce: &str, msg: &str) -> bool {
        let mut vs = vec![self.token.as_str(), timestamp, nonce, msg];
        vs.sort(); // 排序

        let str = vs.join(""); // 拼接字符串,中间不能有其它符号

        // 进行 sha1 校验判断
        if signature == util_string::sha1(&str) {
            true
        } else {
            false
        }
    }

    /// 解密微信消息体(aes 解密)
    /// 1. TmpMsg = Base64_Decode(msg_encrypt)
    /// 2. FullStr = AES_Decrypt(TmpMsg, AESKey);  FullStr 如前所述由4部分组成（random, msg_len, msg, appid）
    /// 3. 验证尾部的appid 是否正确（可选）
    /// 4. 去掉FullStr头部16字节的random、4字节的msg_len、和尾部的appid，即得到明文内容
    #[allow(dead_code)]
    fn aes_decrypt_weixin_msg(&self, str: &str) -> Result<String, MyErr> {
        let msg_data = util_string::base64_decode(str)?; // 对消息文本做base64解码。得到 u8 数组数据
        let key_data = util_string::base64_decode(format!("{}=", self.aeskey).as_str())?; // 对密钥key做base64解码。得到 u8 数组数据

        if msg_data.len() % key_data.len() == 0 {
            let rs = util_string::aes256_cbc_decrypt(msg_data.as_slice(), key_data.as_slice());
            match rs {
                Ok(dec_data) => {
                    if dec_data.len() > 32 {
                        let dec_arry = dec_data.as_slice();
                        // 获取内容长度(16-20 4字节为内容长度，使用高字节序)
                        let msg_len = util::bytes_be_to_u32([dec_arry[16], dec_arry[17], dec_arry[18], dec_arry[19]]) as usize;

                        let dec_str = String::from_utf8_lossy(&dec_arry[20..20 + msg_len]);
                        log::info!("解密后的字符串:[{}]", dec_str);
                        Ok(dec_str.to_string())
                    } else {
                        Err(MyErr::Msg("解密后的内容长度有误".to_string()))
                    }
                }
                Err(e) => Err(MyErr::Msg(format!("解密失败，错误：{:?}", e))),
            }
        } else {
            Err(MyErr::Msg("需要解密的字符串长度验证有误".to_string()))
        }
    }
}

#[allow(dead_code)]
async fn post_json_to_url(url: &str, data: Value) -> Result<Value, MyErr> {
    let client = reqwest::Client::new();
    let rs = client.post(url).json(&data).send().await;
    match rs {
        Ok(res) => match res.json::<serde_json::Value>().await {
            Ok(v) => Ok(v),
            Err(e) => {
                log::error!("读取URL数据失败！错误：{:?} url:{} post_json:{:?}", e, url, data);
                Err(MyErr::Msg("网络异常！".to_string()))
            }
        },
        Err(e) => {
            log::error!("连接url地址失败！错误：{:?} url:{} post_json:{:?}", e, url, data);
            Err(MyErr::Msg("网络异常！".to_string()))
        }
    }
}

#[allow(dead_code)]
async fn get_json_to_url(url: &str) -> Result<Value, MyErr> {
    let client = reqwest::Client::new();
    let rs = client.get(url).send().await;
    match rs {
        Ok(res) => match res.json::<serde_json::Value>().await {
            Ok(v) => Ok(v),
            Err(e) => {
                log::error!("读取URL数据失败！错误：{:?} url:{} ", e, url);
                Err(MyErr::Msg("网络异常！".to_string()))
            }
        },
        Err(e) => {
            log::error!("连接url地址失败！错误：{:?} url:{} ", e, url);
            Err(MyErr::Msg("网络异常！".to_string()))
        }
    }
}
